ggplot2 plot의 기본 성분| 성분 | 설명 |
|---|---|
| Data | 주로 dataframe 형태의 데이터 |
| Aesthetic Mappings | 데이터를 축, 색상 및 점의 크기 등으로 매핑하는 방법 |
| Geometric object | 점,선,도형과 같은 기하학적 객체 |
| Facetting | 조건부 플롯을 위해 패널을 분할하여 표현하는 방법 |
| Statistical transformation | 구간화, 분위수, 평활 등의 통계 변환 |
| Scales | 데이터의 스케일을 동적으로 조정하여 어떤 시각적 요소를 사용할 것인가 정의(e.g., 남성 = 파랑, 여성= 빨강 등으로 지정) |
| Coordinate system | 좌표계 |
| Position adjustment | 위치의 조정 |
ggplot2 함수 분류| 함수 | 설명 |
|---|---|
| plot creation | ggplot 객체를 생성하는 함수군 |
| geoms | 그래픽의 지오메트릭(기하학적인 형태)을 지정하고 추가하는 함수군 |
| statistics | 데이터를 통계적인 관점으로 변환하는 함수군 |
| scales | 축의 스케일 변환과 라벨, 범례 등을 변경하는 함수군 |
| coordinate systems | 좌표계를 설정하는 함수군 |
| faceting | 그래픽 facet 레이아웃을 정의하는 함수군 |
| position adjustments | 지오메트릭의 위치를 지정하는 함수군 |
| anotation | 주석을 표기하는 함수군 |
| fortify | 타 클래스 객체를 데이터 프레임 객체로 변환하는 함수군 |
| themes | 스타일이나 테마를 설정하는 함수군 |
| aesthetics | 데이터를 축, 라벨, 색상 등 기하 구조상 시각적 속성에 매핑하는 함수군 |
| others | 기타 함수군 |
| 레이어 | 함수 |
|---|---|
| data | plot creation 함수군 |
| mapping | plot creation 함수군, aesthetics 함수군 |
| geom | geoms 함수군 |
| stat | statistics 함수군 |
| position | position adjustments 함수군 |
ggplot()과
qplot()
qplot() 함수는 geom을 지정하지 않을 경우 point로
적용됨| 함수 | 설명 | 비고 |
|---|---|---|
geom_point() |
산점도 | |
geom abline() |
추세선 | 기울기와 절편을 꼭 적어줘야 함 |
geom_bar() |
막대그래프 | 이산형 변수화 해야 함 |
geom_ribbon() |
영역을 채우는 plot | geom_area()은 geom_ribbon의 한 형태 |
geom boxplot() |
박스플롯 | |
geom _histogram() |
히스토그램 | |
geom_density() |
1차원 데이터에 대한 밀도를 표현하기 위한 함수 | geom_area() + stat_density()와 동일 |
geom _density2d() |
2차원 데이터에 대한 밀도를 표현하는 함수 | geom_area()+stat_density2d()와 동일. 하지만 복잡한
표현을 하려면 stat_density2d()를 직접 사용해야 함 |
geom_contour() |
등고선을 그리는 용도 | |
geom_text() |
plot에 text를 표현하기 위한 함수 | |
geom_map() |
지도를 표현하는 함수 |
ggplot 객체의 구조 - summary를 보면
대략적인 그래프를 짐작할 수 있음 - mapping을 보면 x,y축의
데이터와 색상을 결정짓는 변수를 확인 가능함 - faceting은
조건부 출력을 의미함. facet_null()’ 은 faceting이 없다는 말 -
geom_point()는 산점도 그래프라는 의미 -
stat_identity는 통계변환이 identity, 즉 변환이 없는 상태의
데이터라는 것을 의미 - position_identity도 데이터 위치가
어떠한 조정도 없었다는 것을 의미 - na.rm=False는 결측값
제거를 하지 않았다는 것을 의미함# install.packages("ggplot2")
# install.packages("titanic")
library(titanic)
titanic.df = titanic_train
titanic.df$Survived = as.factor(titanic.df$Survived)
titanic.df$Pclass = as.factor(titanic.df$Pclass)
titanic.df$Sex = as.factor(titanic.df$Sex)
titanic.df$Embarked = as.factor(titanic.df$Embarked)
titanic.df$NumRelatives = titanic.df$SibSp + titanic.df$Parch
library(ggplot2)
colour = 인수 사용,
barplot =은 색상 옵션으로 fill = 인수
사용#Survival rates
ggplot(data = titanic.df, aes(x = Survived)) + geom_bar()
# Survival rate by gender
ggplot(data = titanic.df, aes(x = Sex, fill = Survived)) + geom_bar()
# Proportions of survival rate by gender
ggplot(data = titanic.df, aes(x = Sex, fill = Survived)) + geom_bar(position = "fill")
# to Survival rate by Passenger class
ggplot(data = titanic.df, aes(x = Pclass, fill = Survived)) + geom_bar()
# Proportions of survival rate by passenger
ggplot(data = titanic.df, aes(x = Pclass, fill = Survived)) + geom_bar(position = "fill")
# Proportions of Passenger class by survival
ggplot(data = titanic.df, aes(x = Survived, fill = Pclass)) + geom_bar(position = "fill")
# Survival rate by gender, but split barplot by Passenger class
ggplot(data = titanic.df, aes(x = Sex, fill = Survived)) +
geom_bar(position = "fill") +
facet_wrap( ~ Pclass)
# <span id="used-example" />
# Survival rate by gender, but split barplot by Passenger class, bars next to each other
ggplot(data = titanic.df, aes(x = Sex, fill = Survived)) +
geom_bar(position = "dodge") +
facet_wrap( ~ Pclass)
# Age Distribution
ggplot(data = titanic.df, aes(x = Age)) + geom_histogram(binwidth = 5)
## Warning: Removed 177 rows containing non-finite values (`stat_bin()`).
# Age Distribution by survival
ggplot(data = titanic.df, aes(x = Age, fill = Survived)) + geom_histogram(binwidth = 5)
## Warning: Removed 177 rows containing non-finite values (`stat_bin()`).
# Age distribution by survival using boxplots
ggplot(data = titanic.df, aes(x = Survived, y = Age)) + geom_boxplot()
## Warning: Removed 177 rows containing non-finite values (`stat_boxplot()`).
# Age distribution by survival and gender using boxplots
ggplot(data = titanic.df, aes(X = Survived, y = Age, fill = Sex)) + geom_boxplot()
## Warning: Removed 177 rows containing non-finite values (`stat_boxplot()`).
# Age Distributions by survival, gender and passenger class using transparent density plots
ggplot(data = titanic.df, aes(x = Age, fill = Survived)) +
facet_grid(Sex ~ Pclass) +
geom_density(alpha = 0.5)
## Warning: Removed 177 rows containing non-finite values (`stat_density()`).
# Age distribution by survival, gender and passenger class using violin plots
ggplot(data = titanic.df, aes(x = Sex, y = Age, fill = Survived)) +
facet_grid( ~ Pclass) +
geom_violin()
## Warning: Removed 177 rows containing non-finite values (`stat_ydensity()`).
# Age VS fare
ggplot(data = titanic.df, aes(x = Age, y = Fare)) + geom_point()
## Warning: Removed 177 rows containing missing values (`geom_point()`).
# Age VS fare, color by survival
ggplot(data = titanic.df, aes(x = Age, y = Fare, color = Survived)) + geom_point()
## Warning: Removed 177 rows containing missing values (`geom_point()`).
# Age VS fare, color by survival, shape by Pclass
ggplot(data = titanic.df, aes(
x = Age,
y = Fare,
color = Survived,
shape =
Pclass
)) +
geom_point(alpha = 0.5)
## Warning: Removed 177 rows containing missing values (`geom_point()`).
# Age VS fare, color by survival, shape by Pclass, size by number of relatives
ggplot(data = titanic.df,
aes(
x = Age,
y = Fare,
color = Survived,
shape =
Pclass,
size = NumRelatives
)) +
geom_point()
## Warning: Removed 177 rows containing missing values (`geom_point()`).
# Age VS fare, color by survival, shape by Pclass, size by number of relatives, semi-transparent points
ggplot(data = titanic.df,
aes(
x = Age,
y = Fare,
color = Survived,
shape =
Pclass,
size = NumRelatives
)) +
geom_point(alpha = 0.5) +
scale_size_continuous(breaks = c(0, 2, 4, 6, 10)) +
scale_color_manual(values = c("red", "yellow"))
## Warning: Removed 177 rows containing missing values (`geom_point()`).
# Age VS number of relatives, color by survival, semi-transparent points
library(devtools)
## Loading required package: usethis
# devtools::install_github("hrbrmstr/ggalt")
library(ggalt)
## Registered S3 methods overwritten by 'ggalt':
## method from
## grid.draw.absoluteGrob ggplot2
## grobHeight.absoluteGrob ggplot2
## grobWidth.absoluteGrob ggplot2
## grobX.absoluteGrob ggplot2
## grobY.absoluteGrob ggplot2
ggplot(data = titanic.df,
aes(x = Age, y = NumRelatives, color = Survived)) +
geom_point(alpha = 0.5, size = 3) +
geom_encircle(data = subset(titanic.df,
Age < 25 & NumRelatives > 4 & Survived == 0),
aes (x = Age, y = NumRelatives))
## Warning: Removed 177 rows containing missing values (`geom_point()`).
# Age VS fare, color by survival, smoothed estimator
ggplot(data = titanic.df, aes(x = Age, y = Fare, color = Survived)) +
geom_point() +
geom_smooth(method = "lm")
## `geom_smooth()` using formula = 'y ~ x'
## Warning: Removed 177 rows containing non-finite values (`stat_smooth()`).
## Removed 177 rows containing missing values (`geom_point()`).
# connect people by Cabin numbers
ggplot(data = subset(titanic.df, Cabin != ""),
aes(x = Age, y = Name, color = Survived)) +
geom_point () +
geom_line(aes(group = Cabin))
## Warning: Removed 19 rows containing missing values (`geom_point()`).
## Warning: Removed 19 rows containing missing values (`geom_line()`).
# Scales (color, fill, size, shape, linetype)
ggplot(data = titanic.df, aes(
x = Age,
y = Fare,
color = Survived,
size = NumRelatives
)) +
geom_point(alpha = 0.5) +
scale_size_continuous(breaks = c(0, 5, 10),
name = "Number of\nrelatives") +
scale_color_manual(labels = c("False", "True"),
values = c("red", "yellow"))
## Warning: Removed 177 rows containing missing values (`geom_point()`).
ggplot(data = titanic.df, aes(
x = Age,
y = Fare,
color = Survived,
size = NumRelatives
)) +
geom_point(alpha = 0.5) +
scale_y_continuous(trans = "log2") +
labs(y = "Fare [$]")
## Warning: Transformation introduced infinite values in continuous y-axis
## Removed 177 rows containing missing values (`geom_point()`).
ggplot(data = titanic.df, aes(
x = Age,
y = Fare,
color = Survived,
size = NumRelatives
)) +
geom_point(alpha = 0.5) +
labs(title = "Age vs. Fare")
## Warning: Removed 177 rows containing missing values (`geom_point()`).
# Flip
ggplot(data = titanic.df, aes(x = Pclass, fill = Survived)) +
geom_bar() +
coord_flip()
# Pie Chart
ggplot(data = titanic.df, aes(x = factor(1), fill = Survived)) +
geom_bar(position = "fill") +
facet_grid(Pclass ~ Sex) +
coord_polar(theta = "y")
# Themes
ggplot(data = titanic.df, aes(
x = Age,
y = Fare,
color = Survived,
size = NumRelatives
)) +
geom_point(alpha = 0.5) +
theme_minimal()
## Warning: Removed 177 rows containing missing values (`geom_point()`).
ggplot(data = titanic.df, aes(
x = Age,
y = Fare,
color = factor(Pclass)
)) +
geom_point () +
geom_smooth(method = "lm")
## `geom_smooth()` using formula = 'y ~ x'
## Warning: Removed 177 rows containing non-finite values (`stat_smooth()`).
## Warning: Removed 177 rows containing missing values (`geom_point()`).
# install.packages('leaflet')
library(leaflet)
library(dplyr)
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
m = leaflet() %>% addTiles()
m %>% setView(127.0462, 37.2830, zoom = 15) #아주대 위경도 설정
m %>% addPopups(127.0462, 37.2830, 'Here is Ajou University!')
m
addTiles() 함수와 addAwesomeMarkers() 함수
사용traffic = read.csv("traffic.csv", fileEncoding = "utf-8")
range (traffic$start.ps.x) # 돌발상황 시작점 경도
## Warning in min(x, na.rm = na.rm): no non-missing arguments to min; returning Inf
## Warning in max(x, na.rm = na.rm): no non-missing arguments to max; returning
## -Inf
## [1] Inf -Inf
range(traffic$start.pos.y) # 돌발상황 시작점 위도
## [1] 0.00000 37.69728
traffic1 = traffic[traffic$start.pos.x != 0 &
traffic$start.pos.y != 0, ] #na값 제거(0인값)
leaflet(traffic1) %>% addTiles() %>%
addAwesomeMarkers( ~ start.pos.x, ~ start.pos.y)
# plotly 예제 코드
library(plotly)
##
## Attaching package: 'plotly'
## The following object is masked from 'package:ggplot2':
##
## last_plot
## The following object is masked from 'package:stats':
##
## filter
## The following object is masked from 'package:graphics':
##
## layout
t = ggplot(iris, aes(Sepal.Length, Sepal.Width, color = Species)) +
geom_point(size = 3)
ggplotly(t)
myplot = ggplot(data = titanic.df, aes(x = Sex, fill = Survived)) +
geom_bar(position = "dodge") +
facet_wrap( ~ Pclass)
ggplotly(myplot)
library(devtools)
# devtools::install_github('charlie86/spotifyr')
library(spotifyr)
Sys.setenv(SPOTIFY_CLIENT_ID = '19adc17a0e6747a4b668b274788c9600')
Sys.setenv(SPOTIFY_CLIENT_SECRET = '83379751536f4d5aa2f8f71d28b58d30')
access_token = get_spotify_access_token()
bts = get_artist_audio_features('BTS')
str(head(bts))
## 'data.frame': 6 obs. of 39 variables:
## $ artist_name : chr "BTS" "BTS" "BTS" "BTS" ...
## $ artist_id : chr "3Nrfpe0tUJi4K4DXYWgMUX" "3Nrfpe0tUJi4K4DXYWgMUX" "3Nrfpe0tUJi4K4DXYWgMUX" "3Nrfpe0tUJi4K4DXYWgMUX" ...
## $ album_id : chr "6al2VdKbb6FIz9d7lU7WRB" "6al2VdKbb6FIz9d7lU7WRB" "6al2VdKbb6FIz9d7lU7WRB" "6al2VdKbb6FIz9d7lU7WRB" ...
## $ album_type : chr "album" "album" "album" "album" ...
## $ album_images :List of 6
## ..$ :'data.frame': 3 obs. of 3 variables:
## .. ..$ height: int 640 300 64
## .. ..$ url : chr "https://i.scdn.co/image/ab67616d0000b27317db30ce3f081d6818a8ad49" "https://i.scdn.co/image/ab67616d00001e0217db30ce3f081d6818a8ad49" "https://i.scdn.co/image/ab67616d0000485117db30ce3f081d6818a8ad49"
## .. ..$ width : int 640 300 64
## ..$ :'data.frame': 3 obs. of 3 variables:
## .. ..$ height: int 640 300 64
## .. ..$ url : chr "https://i.scdn.co/image/ab67616d0000b27317db30ce3f081d6818a8ad49" "https://i.scdn.co/image/ab67616d00001e0217db30ce3f081d6818a8ad49" "https://i.scdn.co/image/ab67616d0000485117db30ce3f081d6818a8ad49"
## .. ..$ width : int 640 300 64
## ..$ :'data.frame': 3 obs. of 3 variables:
## .. ..$ height: int 640 300 64
## .. ..$ url : chr "https://i.scdn.co/image/ab67616d0000b27317db30ce3f081d6818a8ad49" "https://i.scdn.co/image/ab67616d00001e0217db30ce3f081d6818a8ad49" "https://i.scdn.co/image/ab67616d0000485117db30ce3f081d6818a8ad49"
## .. ..$ width : int 640 300 64
## ..$ :'data.frame': 3 obs. of 3 variables:
## .. ..$ height: int 640 300 64
## .. ..$ url : chr "https://i.scdn.co/image/ab67616d0000b27317db30ce3f081d6818a8ad49" "https://i.scdn.co/image/ab67616d00001e0217db30ce3f081d6818a8ad49" "https://i.scdn.co/image/ab67616d0000485117db30ce3f081d6818a8ad49"
## .. ..$ width : int 640 300 64
## ..$ :'data.frame': 3 obs. of 3 variables:
## .. ..$ height: int 640 300 64
## .. ..$ url : chr "https://i.scdn.co/image/ab67616d0000b27317db30ce3f081d6818a8ad49" "https://i.scdn.co/image/ab67616d00001e0217db30ce3f081d6818a8ad49" "https://i.scdn.co/image/ab67616d0000485117db30ce3f081d6818a8ad49"
## .. ..$ width : int 640 300 64
## ..$ :'data.frame': 3 obs. of 3 variables:
## .. ..$ height: int 640 300 64
## .. ..$ url : chr "https://i.scdn.co/image/ab67616d0000b27317db30ce3f081d6818a8ad49" "https://i.scdn.co/image/ab67616d00001e0217db30ce3f081d6818a8ad49" "https://i.scdn.co/image/ab67616d0000485117db30ce3f081d6818a8ad49"
## .. ..$ width : int 640 300 64
## $ album_release_date : chr "2022-06-10" "2022-06-10" "2022-06-10" "2022-06-10" ...
## $ album_release_year : num 2022 2022 2022 2022 2022 ...
## $ album_release_date_precision: chr "day" "day" "day" "day" ...
## $ danceability : num 0.602 0.438 0.597 0.492 0.734 0.482
## $ energy : num 0.841 0.864 0.909 0.931 0.848 0.858
## $ key : int 8 2 11 9 1 5
## $ loudness : num -3.33 -5.18 -4.5 -3.84 -4.43 ...
## $ mode : int 0 1 0 0 1 0
## $ speechiness : num 0.109 0.47 0.16 0.297 0.102 0.069
## $ acousticness : num 0.0354 0.0118 0.0443 0.00244 0.000913 0.0218
## $ instrumentalness : num 0.00 1.66e-06 0.00 0.00 2.47e-04 0.00
## $ liveness : num 0.235 0.431 0.374 0.353 0.256 0.244
## $ valence : num 0.684 0.594 0.564 0.444 0.37 0.737
## $ tempo : num 158 168 147 166 112 ...
## $ track_id : chr "1IthE5GNiRzFN5CVaCa445" "27S8iOXD7Z58yvJtyk2S9j" "2GEnvQgSJhedm2sqZlOP8o" "0vMk4IrUfSJQkhwZnVX6us" ...
## $ analysis_url : chr "https://api.spotify.com/v1/audio-analysis/1IthE5GNiRzFN5CVaCa445" "https://api.spotify.com/v1/audio-analysis/27S8iOXD7Z58yvJtyk2S9j" "https://api.spotify.com/v1/audio-analysis/2GEnvQgSJhedm2sqZlOP8o" "https://api.spotify.com/v1/audio-analysis/0vMk4IrUfSJQkhwZnVX6us" ...
## $ time_signature : int 4 4 4 4 4 4
## $ artists :List of 6
## ..$ :'data.frame': 1 obs. of 6 variables:
## .. ..$ href : chr "https://api.spotify.com/v1/artists/3Nrfpe0tUJi4K4DXYWgMUX"
## .. ..$ id : chr "3Nrfpe0tUJi4K4DXYWgMUX"
## .. ..$ name : chr "BTS"
## .. ..$ type : chr "artist"
## .. ..$ uri : chr "spotify:artist:3Nrfpe0tUJi4K4DXYWgMUX"
## .. ..$ external_urls.spotify: chr "https://open.spotify.com/artist/3Nrfpe0tUJi4K4DXYWgMUX"
## ..$ :'data.frame': 1 obs. of 6 variables:
## .. ..$ href : chr "https://api.spotify.com/v1/artists/3Nrfpe0tUJi4K4DXYWgMUX"
## .. ..$ id : chr "3Nrfpe0tUJi4K4DXYWgMUX"
## .. ..$ name : chr "BTS"
## .. ..$ type : chr "artist"
## .. ..$ uri : chr "spotify:artist:3Nrfpe0tUJi4K4DXYWgMUX"
## .. ..$ external_urls.spotify: chr "https://open.spotify.com/artist/3Nrfpe0tUJi4K4DXYWgMUX"
## ..$ :'data.frame': 1 obs. of 6 variables:
## .. ..$ href : chr "https://api.spotify.com/v1/artists/3Nrfpe0tUJi4K4DXYWgMUX"
## .. ..$ id : chr "3Nrfpe0tUJi4K4DXYWgMUX"
## .. ..$ name : chr "BTS"
## .. ..$ type : chr "artist"
## .. ..$ uri : chr "spotify:artist:3Nrfpe0tUJi4K4DXYWgMUX"
## .. ..$ external_urls.spotify: chr "https://open.spotify.com/artist/3Nrfpe0tUJi4K4DXYWgMUX"
## ..$ :'data.frame': 1 obs. of 6 variables:
## .. ..$ href : chr "https://api.spotify.com/v1/artists/3Nrfpe0tUJi4K4DXYWgMUX"
## .. ..$ id : chr "3Nrfpe0tUJi4K4DXYWgMUX"
## .. ..$ name : chr "BTS"
## .. ..$ type : chr "artist"
## .. ..$ uri : chr "spotify:artist:3Nrfpe0tUJi4K4DXYWgMUX"
## .. ..$ external_urls.spotify: chr "https://open.spotify.com/artist/3Nrfpe0tUJi4K4DXYWgMUX"
## ..$ :'data.frame': 1 obs. of 6 variables:
## .. ..$ href : chr "https://api.spotify.com/v1/artists/3Nrfpe0tUJi4K4DXYWgMUX"
## .. ..$ id : chr "3Nrfpe0tUJi4K4DXYWgMUX"
## .. ..$ name : chr "BTS"
## .. ..$ type : chr "artist"
## .. ..$ uri : chr "spotify:artist:3Nrfpe0tUJi4K4DXYWgMUX"
## .. ..$ external_urls.spotify: chr "https://open.spotify.com/artist/3Nrfpe0tUJi4K4DXYWgMUX"
## ..$ :'data.frame': 1 obs. of 6 variables:
## .. ..$ href : chr "https://api.spotify.com/v1/artists/3Nrfpe0tUJi4K4DXYWgMUX"
## .. ..$ id : chr "3Nrfpe0tUJi4K4DXYWgMUX"
## .. ..$ name : chr "BTS"
## .. ..$ type : chr "artist"
## .. ..$ uri : chr "spotify:artist:3Nrfpe0tUJi4K4DXYWgMUX"
## .. ..$ external_urls.spotify: chr "https://open.spotify.com/artist/3Nrfpe0tUJi4K4DXYWgMUX"
## $ available_markets :List of 6
## ..$ : chr "AD" "AE" "AG" "AL" ...
## ..$ : chr "AD" "AE" "AG" "AL" ...
## ..$ : chr "AD" "AE" "AG" "AL" ...
## ..$ : chr "AD" "AE" "AG" "AL" ...
## ..$ : chr "AD" "AE" "AG" "AL" ...
## ..$ : chr "AD" "AE" "AG" "AL" ...
## $ disc_number : int 1 1 1 1 1 1
## $ duration_ms : int 238628 222066 209751 231384 245810 210986
## $ explicit : logi FALSE FALSE FALSE FALSE FALSE FALSE
## $ track_href : chr "https://api.spotify.com/v1/tracks/1IthE5GNiRzFN5CVaCa445" "https://api.spotify.com/v1/tracks/27S8iOXD7Z58yvJtyk2S9j" "https://api.spotify.com/v1/tracks/2GEnvQgSJhedm2sqZlOP8o" "https://api.spotify.com/v1/tracks/0vMk4IrUfSJQkhwZnVX6us" ...
## $ is_local : logi FALSE FALSE FALSE FALSE FALSE FALSE
## $ track_name : chr "Born Singer" "No More Dream" "N.O" "Boy In Luv" ...
## $ track_preview_url : chr "https://p.scdn.co/mp3-preview/f4b4b5806ad3c8cbe347e227a42adbe336c35653?cid=19adc17a0e6747a4b668b274788c9600" "https://p.scdn.co/mp3-preview/bd2ff7e299b98b3b6ae82e06cdd70178ebf61960?cid=19adc17a0e6747a4b668b274788c9600" "https://p.scdn.co/mp3-preview/15f4cc196f047e216bf54d4e239ce6178cae85ee?cid=19adc17a0e6747a4b668b274788c9600" "https://p.scdn.co/mp3-preview/b96512be866a9407acba1dfb74194c5a55e399b7?cid=19adc17a0e6747a4b668b274788c9600" ...
## $ track_number : int 1 2 3 4 5 6
## $ type : chr "track" "track" "track" "track" ...
## $ track_uri : chr "spotify:track:1IthE5GNiRzFN5CVaCa445" "spotify:track:27S8iOXD7Z58yvJtyk2S9j" "spotify:track:2GEnvQgSJhedm2sqZlOP8o" "spotify:track:0vMk4IrUfSJQkhwZnVX6us" ...
## $ external_urls.spotify : chr "https://open.spotify.com/track/1IthE5GNiRzFN5CVaCa445" "https://open.spotify.com/track/27S8iOXD7Z58yvJtyk2S9j" "https://open.spotify.com/track/2GEnvQgSJhedm2sqZlOP8o" "https://open.spotify.com/track/0vMk4IrUfSJQkhwZnVX6us" ...
## $ album_name : chr "Proof" "Proof" "Proof" "Proof" ...
## $ key_name : chr "G#" "D" "B" "A" ...
## $ mode_name : chr "minor" "major" "minor" "minor" ...
## $ key_mode : chr "G# minor" "D major" "B minor" "A minor" ...
아래 도표는 BTS가 출시한 곡들을 스포티파이의 API에 질의하여 얻은
데이터를 바탕으로 어떤 음계가 몇 회 사용되었는지를 나타냅니다. 이를 통해
가장 빈번히 사용된 음계는 C#이며, 가장 드물게 사용된 음계는
D#임을 알 수 있습니다. 이 도표를 사용하여 아래와 같은
대화를 나눌 수 있습니다.
BTS가 가장 빈번하게 사용한 음계는 무엇입니까?
A. BTS가 가장 빈번히 사용한 음계는 C#으로, 81 개의
곡에서 사용되었습니다.
library(dplyr)
bts$key_name = as.factor(bts$key_name)
table(bts$key_name)
##
## A A# B C C# D D# E F F# G G#
## 45 30 40 50 81 55 17 21 44 62 38 45
ggplot(data = bts, aes(x = as.factor(key_name))) + geom_bar()
아래 도표는 윤하(1988)가 출시한 곡들을 스포티파이의 API에 질의하여 얻은 데이터를 바탕으로 energy 값을 x축으로, valence 값을 y축으로 하여 생성하였습니다. 점들의 위치를 살펴보면 energy와 valence는 양의 상관계수를 가지고 있음을 알 수 있습니다. 이 도표를 사용하여 아래와 같은 대화를 나눌 수 있습니다.
윤하의 곡들에 있어 energy 값과 valence 값은 관계가 있습니까?
A. 윤하의 곡들에 있어 energy 값과 valence 값은 상관게수가
.5975147로써 양의 상관관계를 가집니다.
이 도표에서 높은 valence는 긍정적 감정을 전달함을 의미합니다.
Valence: A measure from 0.0 to 1.0 describing the musical positiveness conveyed by a track. Tracks with high valence sound more positive (e.g. happy, cheerful, euphoric), while tracks with low valence sound more negative (e.g. sad, depressed, angry).
이 도표에서 높은 energy는 빠르고 시끄럽다는 것을 의미합니다.
Energy: Energy is a measure from 0.0 to 1.0 and represents a perceptual measure of intensity and activity. Typically, energetic tracks feel fast, loud, and noisy.
인자에 대한 설명의 출처: https://rpubs.com/mary18/860196
younha = get_artist_audio_features('Younha')
younha$key_name = as.factor(younha$key_name)
# colnames(younha)
with(younha, cor(energy, valence))
## [1] 0.5975147
ggplot(data = younha, aes(x = energy, y = valence)) +
geom_point(alpha = 0.6) +
geom_smooth(method = 'lm', aes(color = "lm"))
## `geom_smooth()` using formula = 'y ~ x'
조금 더 대량의 데이터를 분석해보기 위해 1960년부터 2015년까지의 빌보드 TOP100에 탑재된 데이터를 가져옵니다. 아래 도표는 탑재된 곡들을 스포티파이의 API에 질의하여 얻은 데이터를 바탕으로 danceability 값을 x축으로, valence 값을 y축으로 하여 생성하였습니다.
cor_df를 활용하여 danceability_valence 간에 양의
상관관계를 발견할 수 있습니다. cor_df에서 얻은
danceability_valence 간의 상관계수가 양의 값을 가지고 있음에 따라 눈으로
어떤 분포를 보이는지 확인하기 위해 두 변수를 사용하여 산점도를
출력합니다. 점들의 위치를 살펴보면 danceability_valence는 양의
상관계수를 가지고 있음을 알 수 있습니다.
energy_loudness 간의 상관관계는 스포티파이에서 이미 보통 energy 값이 높을수록 loud하다고 밝혔으므로 제외하였습니다.
빌보드 TOP100 플레이리스트 출처: https://github.com/mikkelkrogsholm/billboard/blob/master/data/spotify_playlists.rda
이 도표에서 높은 danceability는 템포, 리듬 안정성, 비트 강도, 전반적인 규칙성을 포함한 음악적 요소의 조합에 기초하여 트랙이 춤을 추기 적합함을 의미합니다.
Danceability: Danceability describes how suitable a track is for dancing based on a combination of musical elements including tempo, rhythm stability, beat strength, and overall regularity.
인자에 대한 설명의 출처: https://rpubs.com/mary18/860196
billboard_spotify_playlists = read.csv('https://raw.githubusercontent.com/khskeb0513/ajou-r-programming/main/spotify_playlists.csv')
billboard_track_ids_list = list()
for (playlist_id in billboard_spotify_playlists$spotify_playlist) {
billboard_track_ids_list[[length(billboard_track_ids_list) + 1]] = get_playlist_tracks(playlist_id)$track.id
}
billboard_tracks_features = tibble()
for (track_ids in billboard_track_ids_list) {
billboard_tracks_features = rbind(billboard_tracks_features,
get_track_audio_features(track_ids))
}
combine_df = data.frame(combn(
c(
"danceability",
"energy",
"key" ,
"loudness",
"speechiness",
"acousticness",
"instrumentalness",
"liveness",
"valence",
"tempo",
"duration_ms"
),
2
))
cor_df = data.frame()
for (combination in combine_df) {
cor_df = rbind(cor_df, data.frame(
combination = paste0(combination[1], '_', combination[2]),
cor = cor(
billboard_tracks_features[[combination[1]]],
billboard_tracks_features[[combination[2]]],
use = 'na.or.complete'
)
))
}
cor_df = cor_df %>% arrange(cor, )
tail(cor_df)
## combination cor
## 50 energy_speechiness 0.1773779
## 51 danceability_energy 0.2111385
## 52 danceability_speechiness 0.2168544
## 53 energy_valence 0.3714116
## 54 danceability_valence 0.4691401
## 55 energy_loudness 0.6828829
ggplot(data = billboard_tracks_features, aes(x = danceability, y = valence)) +
geom_point(alpha = 1 / 20) +
geom_smooth(method = 'lm', aes(color = "lm"))
## `geom_smooth()` using formula = 'y ~ x'
## Warning: Removed 3 rows containing non-finite values (`stat_smooth()`).
## Warning: Removed 3 rows containing missing values (`geom_point()`).
library(tidyverse)
## ── Attaching packages ─────────────────────────────────────── tidyverse 1.3.2 ──
## ✔ tibble 3.1.8 ✔ purrr 0.3.5
## ✔ tidyr 1.2.1 ✔ stringr 1.4.1
## ✔ readr 2.1.3 ✔ forcats 0.5.2
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ plotly::filter() masks dplyr::filter(), stats::filter()
## ✖ dplyr::lag() masks stats::lag()
# 변수(variable)는 측정할 수 있는 양, 질 또는 속성이다.
# 값(value)은 변수가 측정될 때의 상태이다. 변수의 값은 측정에 따라 변할 수 있다.
# 관측값(observation)(또는 사례(case))은 유사한 조건에서 측정된 값들의 집합이다 (일반적으로 동시에 같은 대상에 대해 모든 관측된 값을 사용한다.). 관측값은 서로 다른 변수가 조합된 다양한 값을 포함한다. 관측값을 데이터 포인트라고 부르기도 한다.
# 테이블 형식의 데이터(Tabular data)는 각 변수들과 관측값의 조합인 값들의 집합이다. 테이블 형식의 데이터는 각 값은 ‘셀’에, 변수들은 열에, 관측값은 행에 있을 때 타이디(tidy)하다고 한다. 지금까지 보았던 모든 데이터는 타이디 데이터였다. 실제로 데이터 대부분은 타이디하지 않기 때문에 tidy data에서는 이 부분에 대해 다시 다룰 것이다.
# 범주형 변수의 분포를 확인하기 위해 막대 그래프를 사용
ggplot(data = diamonds) + geom_bar(mapping = aes(x = cut))
# 수동으로 계산
diamonds %>% count(cut)
## # A tibble: 5 × 2
## cut n
## <ord> <int>
## 1 Fair 1610
## 2 Good 4906
## 3 Very Good 12082
## 4 Premium 13791
## 5 Ideal 21551
# 연속형 변수의 분포를 확인하기 위해 막대 히스토그램을 사용
ggplot(data = diamonds) + geom_histogram(mapping = aes(x = carat), binwidth = 0.5)
# 연속형 변수를 0.5 단위로 범주화하여 수동으로 계싼
diamonds %>% count(cut_width(carat, 0.5))
## # A tibble: 11 × 2
## `cut_width(carat, 0.5)` n
## <fct> <int>
## 1 [-0.25,0.25] 785
## 2 (0.25,0.75] 29498
## 3 (0.75,1.25] 15977
## 4 (1.25,1.75] 5313
## 5 (1.75,2.25] 2002
## 6 (2.25,2.75] 322
## 7 (2.75,3.25] 32
## 8 (3.25,3.75] 5
## 9 (3.75,4.25] 4
## 10 (4.25,4.75] 1
## 11 (4.75,5.25] 1
# 3캐럿 미만의 다이아몬드로 범위를 줄이고 binwidth를 다르게 하여 막대 히스토그램 생성
smaller <- diamonds %>%
filter(carat < 3)
ggplot(data = smaller, mapping = aes(x = carat)) +
geom_histogram(binwidth = 0.1)
# 하나의 플롯에서 여러 개의 히스토그램을 보기 위해 선 히스토그램 생성
ggplot(data = smaller, mapping = aes(x = carat, colour = cut)) +
geom_freqpoly(binwidth = 0.1)
# 3 캐럿보다 큰 다이아몬드는 없다
ggplot(data = smaller, mapping = aes(x = carat)) +
geom_histogram(binwidth = 0.01)
# 272 번의 화산분출은 크게 2 개의 그룹으로 묶을 수 있다
ggplot(data = faithful, mapping = aes(x = eruptions)) +
geom_histogram(binwidth = 0.25)
# 0.5 단위로 나누었을 때 개수가 50 개 이하인 범주를 확인
ggplot(diamonds) +
geom_histogram(mapping = aes(x = y), binwidth = 0.5) +
coord_cartesian(ylim = c(0, 50))
# 다이아몬드는 y축 값이 3mm 미만, 20mm 초과인 경우 이상치라고 볼 수 있다
diamonds %>%
filter(y < 3 | y > 20) %>%
select(price, x, y, z) %>%
arrange(y)
## # A tibble: 9 × 4
## price x y z
## <int> <dbl> <dbl> <dbl>
## 1 5139 0 0 0
## 2 6381 0 0 0
## 3 12800 0 0 0
## 4 15686 0 0 0
## 5 18034 0 0 0
## 6 2130 0 0 0
## 7 2130 0 0 0
## 8 2075 5.15 31.8 5.12
## 9 12210 8.09 58.9 8.06
# 이상값이 결과에 최소한의 영향을 미치고 왜 이상값이 발생했는지 그 이유를 알 수 없다면 결측값으로 대체한 후 계속 진행하는 것이 합리적이다. 그러나 이상값이 결과에 상당한 영향을 미치는 경우, 타당한 이유 없이 제외해서는 안 된다. 문제의 원인(예, 데이터 입력 오류)을 파악하고 이상값을 제거한 사실을 밝혀야 한다.
# 이상 값이 포함된 행 전체 삭제
diamonds2 <- diamonds %>% filter(between(y, 3, 20))
# 이상 값을 결측값으로 변경
diamonds2 <- diamonds %>% mutate(y = ifelse(y < 3 | y > 20, NA, y))
# ggplot2은 결측치가 포함된 데이터가 인입되었을 시 경고를 표시한다. 이를 제거하려면 na.rm 인자를 TRUE로 설정
ggplot(data = diamonds2, mapping = aes(x = x, y = y)) +
geom_point()
## Warning: Removed 9 rows containing missing values (`geom_point()`).
# 결측값은 결측값이 아닌 행과 차이를 만들고 싶어 설정하는 경우도 있다.
# nycflights13::flights 에서 dep_time 변수의 결측값은 항공기의 운항이 취소되었다는 것을 나타낸다.
# dep_time는 출발 시각을 의미
# dep_time을 15분 단위로 쪼개어서 운항 / 결항으로 나누어 그 갯수를 표시한 모습. 결항의 전체 갯수가 적어 가시적으로 비교가 어렵다.
# install.packages('nycflights13')
library(nycflights13)
nycflights13::flights %>%
mutate(
cancelled = is.na(dep_time),
sched_hour = sched_dep_time %/% 100,
sched_min = sched_dep_time %% 100,
sched_dep_time = sched_hour + sched_min / 60
) %>%
ggplot(mapping = aes(sched_dep_time)) +
geom_freqpoly(mapping = aes(colour = cancelled), binwidth = 1 / 4)
# 전체적인 빈도 수가 다르다
ggplot(diamonds) +
geom_bar(mapping = aes(x = cut))
# 전체적인 빈도 수가 크게 달라 다이아몬드의 가격과 품질 간 관계를 파악하기 어렵다
ggplot(data = diamonds, mapping = aes(x = price)) +
geom_freqpoly(mapping = aes(colour = cut), binwidth = 500)
# 품질 별 상대도수 히스토그램을 통해 품질 별 가격대 분포를 확인할 수 있다
ggplot(data = diamonds, mapping = aes(x = price, y = after_stat(density))) +
geom_freqpoly(mapping = aes(colour = cut), binwidth = 500)
# 박스플롯을 그려 같은 기능을 수행할 수 있다
ggplot(data = diamonds, mapping = aes(x = cut, y = price)) +
geom_boxplot()
# 번주형 변수들의 공변동은 관측 값 수를 세서 시각화할 수 있다. 관측 값 수는 원의 크기로 표시하고 있다
ggplot(data = diamonds) +
geom_count(mapping = aes(x = cut, y = color))
# 혹은 수동으로 갯수를 세서 시각화할 수 있다
diamonds %>%
count(color, cut) %>%
ggplot(mapping = aes(x = color, y = cut)) +
geom_tile(mapping = aes(fill = n))
# 데이터셋이 큰 산점도의 경우 alpha 인자를 통해 투명도의 추가를 고려할 수 있다
# 투명도 설정 전
ggplot(data = diamonds) +
geom_point(mapping = aes(x = carat, y = price))
# 투명도 설정 후
ggplot(data = diamonds) +
geom_point(mapping = aes(x = carat, y = price), alpha = 1 / 100)
# hexbin 패키지는 좌표 평면을 2D bin 으로 나눈 뒤, 값을 색상의 진하기로 표시한다
# 직사각형 빈을 만드는 경우
ggplot(data = smaller) +
geom_bin2d(mapping = aes(x = carat, y = price))
# 육각형 빈을 만드는 경우
# install.packages("hexbin")
ggplot(data = smaller) +
geom_hex(mapping = aes(x = carat, y = price))
# 연속형 변수를 그룹화하여 범주형 변수로 만드는 방법도 있다. 이를 박스 플롯으로 그릴 수 있다
ggplot(data = smaller, mapping = aes(x = carat, y = price)) +
geom_boxplot(mapping = aes(group = cut_width(carat, 0.1)))
# 캐럿을 20 부분으로 범주화하여 표시
ggplot(data = smaller, mapping = aes(x = carat, y = price)) +
geom_boxplot(mapping = aes(group = cut_number(carat, 20)))
# Old Faithful 분출 시간과 분출 사이의 시간 사이의 산점도
# 분출 사이의 대기 시간이 길수록 분출 시간도 길어지는 패턴을 보인다.
ggplot(data = faithful) +
geom_point(mapping = aes(x = eruptions, y = waiting))
# 예를 들어 다이아몬드 데이터를 생각해보자. 컷팅과 캐럿 그리고 캐럿과 가격은 밀접하게 관련되어 있으므로 컷팅과 가격의 상관관계를 이해하기 어렵다. 모델을 활용하여 가격과 캐럿 간의 매우 강력한 상관관계를 제거하면 남아있는 중요한 세부 요소들을 탐색할 수 있다. 다음 코드에서는 carat 으로 price 를 예측하는 모델을 적합시킨 다음, 잔차(예측값과 실제값의 차이)를 계산한다. 캐럿의 효과가 제거되면 잔차는 다이아몬드의 가격에 대한 관점을 제공한다.
# 윌킨슨 표기법을 사용하여 모델식을 지정합니다. log(carat)를 예측 변수로 사용하여 log(price)에 대한 선형 회귀 모델을 피팅합니다. fitlm하고 기능이 같은 듯...
# 다이아몬드의 price의 로그 값을 반응변수(종속변수), carat의 로그 값을 독립변수(설명변수)로 하여 단순회귀모형(linear model) 계산
mod <- diamonds %>% lm(formula = log(price) ~ log(carat))
str(mod)
## List of 12
## $ coefficients : Named num [1:2] 8.45 1.68
## ..- attr(*, "names")= chr [1:2] "(Intercept)" "log(carat)"
## $ residuals : Named num [1:53940] -0.1989 -0.0464 -0.1958 -0.5631 -0.6718 ...
## ..- attr(*, "names")= chr [1:53940] "1" "2" "3" "4" ...
## $ effects : Named num [1:53940] -1808.476 227.618 -0.195 -0.562 -0.671 ...
## ..- attr(*, "names")= chr [1:53940] "(Intercept)" "log(carat)" "" "" ...
## $ rank : int 2
## $ fitted.values: Named num [1:53940] 5.99 5.83 5.99 6.37 6.49 ...
## ..- attr(*, "names")= chr [1:53940] "1" "2" "3" "4" ...
## $ assign : int [1:2] 0 1
## $ qr :List of 5
## ..$ qr : num [1:53940, 1:2] -2.32e+02 4.31e-03 4.31e-03 4.31e-03 4.31e-03 ...
## .. ..- attr(*, "dimnames")=List of 2
## .. .. ..$ : chr [1:53940] "1" "2" "3" "4" ...
## .. .. ..$ : chr [1:2] "(Intercept)" "log(carat)"
## .. ..- attr(*, "assign")= int [1:2] 0 1
## ..$ qraux: num [1:2] 1 1.01
## ..$ pivot: int [1:2] 1 2
## ..$ tol : num 1e-07
## ..$ rank : int 2
## ..- attr(*, "class")= chr "qr"
## $ df.residual : int 53938
## $ xlevels : Named list()
## $ call : language lm(formula = log(price) ~ log(carat), data = .)
## $ terms :Classes 'terms', 'formula' language log(price) ~ log(carat)
## .. ..- attr(*, "variables")= language list(log(price), log(carat))
## .. ..- attr(*, "factors")= int [1:2, 1] 0 1
## .. .. ..- attr(*, "dimnames")=List of 2
## .. .. .. ..$ : chr [1:2] "log(price)" "log(carat)"
## .. .. .. ..$ : chr "log(carat)"
## .. ..- attr(*, "term.labels")= chr "log(carat)"
## .. ..- attr(*, "order")= int 1
## .. ..- attr(*, "intercept")= int 1
## .. ..- attr(*, "response")= int 1
## .. ..- attr(*, ".Environment")=<environment: 0x7fe742ca2a30>
## .. ..- attr(*, "predvars")= language list(log(price), log(carat))
## .. ..- attr(*, "dataClasses")= Named chr [1:2] "numeric" "numeric"
## .. .. ..- attr(*, "names")= chr [1:2] "log(price)" "log(carat)"
## $ model :'data.frame': 53940 obs. of 2 variables:
## ..$ log(price): num [1:53940] 5.79 5.79 5.79 5.81 5.81 ...
## ..$ log(carat): num [1:53940] -1.47 -1.56 -1.47 -1.24 -1.17 ...
## ..- attr(*, "terms")=Classes 'terms', 'formula' language log(price) ~ log(carat)
## .. .. ..- attr(*, "variables")= language list(log(price), log(carat))
## .. .. ..- attr(*, "factors")= int [1:2, 1] 0 1
## .. .. .. ..- attr(*, "dimnames")=List of 2
## .. .. .. .. ..$ : chr [1:2] "log(price)" "log(carat)"
## .. .. .. .. ..$ : chr "log(carat)"
## .. .. ..- attr(*, "term.labels")= chr "log(carat)"
## .. .. ..- attr(*, "order")= int 1
## .. .. ..- attr(*, "intercept")= int 1
## .. .. ..- attr(*, "response")= int 1
## .. .. ..- attr(*, ".Environment")=<environment: 0x7fe742ca2a30>
## .. .. ..- attr(*, "predvars")= language list(log(price), log(carat))
## .. .. ..- attr(*, "dataClasses")= Named chr [1:2] "numeric" "numeric"
## .. .. .. ..- attr(*, "names")= chr [1:2] "log(price)" "log(carat)"
## - attr(*, "class")= chr "lm"
# mod 모형에서 잔차 값을 가져와 자연로그의 밑으로 취해 resid 열의 값으로 설정
diamonds2 <- diamonds %>%
modelr::add_residuals(mod) %>%
mutate(resid = exp(resid))
# 그래프 생성
ggplot(data = diamonds2) +
geom_point(mapping = aes(x = carat, y = resid))
# 커팅과 가격의 상관관계(다이아몬드의 크기에 비례하여 우수한 품질의 다이아몬드가 더 비싸다)
ggplot(data = diamonds2) +
geom_boxplot(mapping = aes(x = cut, y = resid))
ggplot(data = faithful, mapping = aes(x = eruptions)) +
geom_freqpoly(binwidth = 0.25)
# 일반적으로 함수의 첫 번째, 두 번째 인수는 매우 중요하므로 기억해두어야 한다. ggplot() 에서 처음 두 개의 인수는 data 와 mapping 인수이며, aes() 의 처음 두 개의 인수는 x 와 y 이다. 이 책의 나머지 부분에서는 이 이름들을 쓰지 않을 것 이다. 이렇게 하면 타이핑이 줄어들고 상용구의 양이 줄어들어 플롯 간에 다른 점을 쉽게 알 수 있다. 이는 27 에서 다루게 될 매우 중요한 프로그래밍 문제 이다.
# 위의 플롯을 좀 더 간결하게 작성하면 다음과 같다.
ggplot(faithful, aes(eruptions)) +
geom_freqpoly(binwidth = 0.25)
# 때때로 데이터를 변환하는 파이프라인의 끝을 플롯으로 전환할 것이다. %>% 에서 + 로 전환되는 것을 유의하자. 이 전환이 필요하지 않으면 좋겠지만 안타깝게도 파이프가 생기기 이전에 ggplot2 가 만들어졌다.
diamonds %>%
count(cut, clarity) %>%
ggplot(aes(clarity, cut, fill = n)) +
geom_tile()